import cv2
import numpy as np
import matplotlib.pyplot as plt
import math

def IsOddNumber(i):
	'''Check if input number is odd number or not'''
	if (i-1)%2 == 0:
		return True
	else:
		return False


def CalculateGuassion(value, mean, var):
	return math.exp(-((value - mean)**2)/(2*(var**2)))/(var*math.sqrt(2*math.pi))


def Flipover(mask):
	'''Rotate mask 180 degree. This method only works for squred matrix. Rows and columns must be odd number. '''
	row, col = mask.shape
	
	if row != col:
		return None
	if not IsOddNumber(row):
		return None

	maxRowIndex = row - 1
	maxColIndex = col - 1

	halfRow = row / 2
	halfCol = col / 2
	
	result = mask.copy()
	for i in range(halfRow):
		for j in range(col):
			result[i,j], result[maxRowIndex-i, maxColIndex-j] = result[maxRowIndex-i, maxColIndex-j], result[i,j]

	i = halfRow
	for j in range(halfCol):
		result[i,j], result[i, maxColIndex-j] = result[i, maxColIndex-j], result[i,j]

	return result


def GenerateMask(size, coefficient):
	'''Generate a size * size mask and filled with coefficient'''
	if not IsOddNumber(size):
		return None

	result = np.zeros((size, size), np.float64)
	result.fill(coefficient)

	return result


# TODO:
def GenerateGuassianMask():
	pass

# TODO:
def GenerateGuassianNoise(rawImg, mean, var):
	noise = rawImg.copy()
	cv2.randn(noise, mean, var);
	result = rawImg.copy()
	return result + noise

# TODO:
def GenerateSaltPepperNoise(rawImg):
	noise = np.zeros(rawImg.shape, np.uint8)
	cv2.randu(noise, 0, 255);
	white = noise < 30
	black = noise > 225

	result = rawImg.copy()
	result.setTo(255, white)
	result.setTo(0, black)
	
	return result + noise


def Convolve(rawImg, mask):
	maskRow, maskCol = mask.shape
	if(maskRow != maskCol) or not IsOddNumber(maskRow):
		return

	flipedMask = Flipover(mask)

	return Correlate(rawImg, flipedMask)
	

def Correlate(rawImg, mask):
	maskRow, maskCol = mask.shape
	maskRadius = (maskRow - 1) / 2

	imgHeight, imgWidth = rawImg.shape
	resultImage = rawImg.copy()

	for i in range(imgHeight):
		for j in range(imgWidth):
			tempSum = 0.0
			for xDelta in range(-maskRadius, maskRadius + 1):
				for yDelta in range(-maskRadius, maskRadius + 1):
					imgX = i + xDelta
					imgY = j + yDelta
					maskX = xDelta + maskRadius
					maskY = yDelta + maskRadius
					
					if ((imgX < 0) or (imgY < 0) or (imgX >= imgHeight) or (imgY >= imgWidth)):
						continue
					else:
						tempSum += rawImg[imgX, imgY] * mask[maskX, maskY]

			resultImage[i,j] = int(round(tempSum))

	return resultImage


def SmoothWithMedianFilter(rawImg, filterSize):
	maskRow, maskCol = (filterSize, filterSize)
	maskRadius = (maskRow - 1) / 2

	imgHeight, imgWidth = rawImg.shape
	resultImage = rawImg.copy()

	for i in range(imgHeight):
		for j in range(imgWidth):
			tempList = []
			for xDelta in range(-maskRadius, maskRadius + 1):
				for yDelta in range(-maskRadius, maskRadius + 1):
					imgX = i + xDelta
					imgY = j + yDelta
					
					if ((imgX < 0) or (imgY < 0) or (imgX >= imgHeight) or (imgY >= imgWidth)):
						tempList.append(0)
					else:
						tempList.append(rawImg[imgX, imgY])
			tempList.sort()

			resultImage[i,j] = templist[len(tempList)/2+1]

	return resultImage




if __name__ == '__main__':
	mask9 = GenerateMask(3, 1/9.0)
	print mask9
	print "======"
	mask25 = GenerateMask(5, 1/25.0)
	print mask25
	
	print "****************************************"
	
	flipedMatrix25 = Flipover(mask25)
	print "Fliped Matrix25: \n"
	print flipedMatrix25
	
	print "****************************************"
	
	rawImg = cv2.imread('./img/fig4.jpg', cv2.CV_LOAD_IMAGE_GRAYSCALE)
	cv2.namedWindow('Original Image', cv2.CV_WINDOW_AUTOSIZE)
	cv2.imshow( "Original Image", rawImg)

	nosiedImage = GenerateGuassianNoise(rawImg, 0, 20)
	cv2.namedWindow('Noised Image', cv2.CV_WINDOW_AUTOSIZE)
	cv2.imshow( "Noised Image", nosiedImage)

	print "****************************************"

	resultImage = cv2.filter2D(nosiedImage,-1,mask9)
	cv2.namedWindow('Smoothed Image by 3*3 with CV2', cv2.CV_WINDOW_AUTOSIZE)
	cv2.imshow( "Smoothed Image by 3*3 with CV2", resultImage)
	
	resultImage = Convolve(nosiedImage, mask9)
	cv2.namedWindow('Smoothed Image by 3*3', cv2.CV_WINDOW_AUTOSIZE)
	cv2.imshow( "Smoothed Image by 3*3", resultImage)

	#resultImage = Convolve(rawImg, mask25)
	#cv2.namedWindow('Smoothed Image by 5*5', cv2.CV_WINDOW_AUTOSIZE)
	#cv2.imshow( "Smoothed Image by 5*5", resultImage)

	#mask0 = GenerateMask(3, 1/15.0)
	#resultImage = Convolve(rawImg, mask0)
	#cv2.namedWindow('Smoothed Image by 3*3 0.04', cv2.CV_WINDOW_AUTOSIZE)
	#cv2.imshow( "Smoothed Image by 3*3 0.04", resultImage)

	cv2.waitKey(0)
	cv2.destroyAllWindows()